#include "netbus.h"
#include "connect_pool.h"
#include <sstream>
#include "provider.h"
#include <mutex>
#include "deliver.h"

NetBus::NetBus() {}

NetBus::~NetBus()
{
    if (connect_pool_)
    {
        delete connect_pool_;
    }
}

NetBus *NetBus::GetInstance()
{
    static NetBus netbus;
    return &netbus;
}

void NetBus::setHost(const std::string &host)
{
    host_ = host;
}

void NetBus::setPort(uint port)
{
    port_ = port;
}

void NetBus::setUsername(const std::string &username)
{
    username_ = username;
}

void NetBus::setPassword(const std::string &password)
{
    password_ = password;
}

void NetBus::setThreadNum(int thread_num)
{
    thread_num_ = thread_num;
}

/**
 * 启动NetBus服务
 * 
 * 该函数负责初始化和启动NetBus的连接池如果连接池尚未创建，
 * 它将根据提供的主机、端口、用户名和密码信息来创建一个新的连接池
 * 并初始化连接池，使其能够处理指定数量的线程
 */
void NetBus::start()
{
    if (!connect_pool_)
    {
        std::stringstream ss;
        ss << "amqp://" << username_ << ":" << password_ << "@" << host_ << ":" << port_;
        
        connect_pool_ = new ConnectPool(ss.str());
        
        // 初始化连接池，使其能够处理指定数量的线程
        connect_pool_->init(thread_num_);
    }
}

/**
 * 向NetBus对象中添加一个Provider。
 * 
 * 此函数首先遍历已有的Provider列表，检查是否有与待添加的Provider具有相同appName和subName的Provider。
 * 如果存在相同名称的Provider，则不添加，返回false。
 * 如果不存在相同名称的Provider，则将该Provider添加到列表中，并将其添加到connect_pool_中，最后返回true。
 * 
 * @param provider 指向要添加的Provider的指针。
 * @return 添加成功返回true，否则返回false。
 */
bool NetBus::addProvider(Provider *provider)
{
    for (auto &p : providers_)
    {
        // 如果发现具有相同appName和subName的Provider，则不添加，直接返回false。
        if (provider->appName() == p->appName() && provider->subName() == p->subName())
        {
            return false;
        }
    }
    // 将新的Provider添加到列表中。
    providers_.push_back(provider);
    // 将新的Provider添加到连接池中。
    connect_pool_->addProvider(provider);
    return true;
}

/**
 * @brief 发送数据给指定的网络地址
 * 
 * 该函数负责将数据包发送到网络上的指定地址它使用连接池来处理网络连接，
 * 并利用条件变量来等待数据发送的回应
 * 
 * @param deliver 包含网络地址和数据的交付对象
 * @return true 如果数据成功发送并收到回应
 * @return false 如果数据发送失败或在指定时间内未收到回应
 */
bool NetBus::send(Deliver *deliver)
{
    connect_pool_->dispatch(deliver);
    
    std::unique_lock<std::mutex> lock(*deliver->mutex());
    
    // 等待数据发送的回应，最多等待5秒
    if (deliver->cond()->wait_for(lock, std::chrono::seconds(5), [deliver]()
                                  { return deliver->isReplied(); }))
    {
        return true;
    }
    
    return false;
}

/**
 * @brief 发送请求并等待响应
 * 
 * 该函数通过网络连接发送请求，并等待响应。它使用连接池来高效管理网络连接。
 * 发送请求后，在指定的时间限制内等待响应。如果在时间限制内收到响应，则返回 true；否则返回 false。
 * 
 * @param deliver 包含请求信息和响应处理逻辑的 Deliver 对象
 * @return 如果在指定时间内收到响应，返回 true；否则返回 false
 */
bool NetBus::sendAndReceived(Deliver *deliver)
{
    connect_pool_->dispatch(deliver);
    
    std::unique_lock<std::mutex> lock(*deliver->mutex());
    
    if (deliver->cond()->wait_for(lock, std::chrono::seconds(5), [deliver]()
                                  { return deliver->isReplied(); }))
    {
        return true;
    }
    
    return false;
}
